package com.alks.common.utils;

import com.alks.entity.exception.UtilsException;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Field;
import java.math.BigDecimal;

import static com.alibaba.excel.util.FieldUtils.nullObjectClass;

@Data
@Slf4j
public class FieldUtils {

    /**
     * 将New结尾数据写入对应数据中，例如remarkNew赋值给remark
     * @param request
     * @param <T>
     * @return
     * @throws IllegalAccessException
     */
    public static <T> T copyNewValuesToOld(T request) throws IllegalAccessException {
        Field[] fields = request.getClass().getDeclaredFields();
        for (Field field : fields) {
            String fieldName = field.getName();
            if (fieldName.endsWith("New")) {
                String oldFieldName = fieldName.substring(0, fieldName.length() - 3);
                Field oldField = getField(request.getClass(), oldFieldName);
                if (oldField != null) {
                    field.setAccessible(true);
                    oldField.setAccessible(true);
                    Object newValue = field.get(request);
                    oldField.set(request, newValue);
                }
            }
        }
        return request;
    }

    private static Field getField(Class<?> clazz, String fieldName) {
        try {
            return clazz.getDeclaredField(fieldName);
        } catch (NoSuchFieldException e) {
            return null;
        }
    }

    /**
     * 根据元素名求和
     * @param clazz 入参类
     * @param data 待求和数据
     * @param filedNames 元素包含的名字
     * @return 求和结果
     * @throws IllegalAccessException 抛异常
     */
    public static BigDecimal getSum(Class<?> clazz, Object data, String... filedNames) throws IllegalAccessException {
        BigDecimal sum = BigDecimal.ZERO;
        Field[] fields = clazz.getFields();
        for (Field field : fields) {
            field.setAccessible(true);
            for (String field1 : filedNames) {
                if (field.getName().contains(field1)) {
                    try {
                        Object o = field.get(data);
                        if (getFieldClass(o).equals(BigDecimal.class)) {
                            sum = sum.add((BigDecimal) o);
                        } else {
                            sum = sum.add(BigDecimal.valueOf((double) o));
                        }
                    } catch (IllegalAccessException e) {
                        errorThrow(field1);
                    }
                }
            }
        }
        return sum;
    }

    /**
     * 根据元素名判空
     * @param clazz 入参类
     * @param data 待判空数据
     * @param num 需要判空的数量（如果为-1则全判空）
     * @param filedNames 元素包含的名字
     * @return 判空结果
     * @throws IllegalAccessException 抛异常
     */
    public static boolean noNull(Class<?> clazz, Object data, int num, String... filedNames) throws IllegalAccessException {
        Field[] fields = clazz.getDeclaredFields();
        boolean allNonNull = true;
        for (Field field : fields) {
            field.setAccessible(true);
            for (String fieldName : filedNames) {
                if (field.getName().contains(fieldName)) {
                    // 检查当前字段的数字部分
                    String fieldString = field.getName();
                    String numberPart = fieldString.replaceAll("\\D+", "");
                    /*如果不需要不包含数字则将-1改成num*/
                    int number = numberPart.isEmpty() ? -1 : Integer.parseInt(numberPart);
                    // 仅检查数值小于num的字段
                    if (num==-1||number <= num) {
                        Object fieldValue = field.get(data);
                        boolean valueNullFlag = fieldValue == null || (fieldValue instanceof String && ((String) fieldValue).isEmpty());
                        if (valueNullFlag) {
                            allNonNull = false;
                            break;
                        }
                    }
                }
            }
        }

        return allNonNull;
    }

    private static void errorThrow(String field){
        String name = new Exception().getStackTrace()[2].getMethodName();
        log.error("\n错误接口：{}\n错误原因：未找到对应元素：{}",name, field);
        throw new UtilsException("反射方法未能找到指定元素："+field);
    }

    public static Class<?> getFieldClass(Object value) {
        return value != null ? value.getClass() : nullObjectClass;
    }

}
